<template>
  <div class="wrap">
    <canvas id="renderCanvas"></canvas>
  </div>
</template>

<script>
import * as BABYLON from "babylonjs"; // 全部引入
import * as GEOLIB from "geolib";
import line2D from "./js/line2D"; // 带有宽度的线
export default {
  name: "building2Com",
  data() {
    return {
      light1: null,
      light2: null,
      sphere: null,
      engine: null,
      scene: null,
      canvas: null,
      myMaterial: null,
      myMaterial2: null,
      lineMat: null,
      buildingMat: null,
      center: [121.5258742, 31.2328371]
    };
  },
  props: {
    msg: String
  },
  beforeDestroy() {
    // this.scene = null;
    // this.engine = null;
    while (this.engine.scenes.length) {
      console.log(this.engine.scenes.length, "让我看看aaaaa");
      this.engine.scenes[0].dispose();
    }
    this.engine.dispose();
    this.engine = null;
  },
  methods: {
    // 获取geo数据
    getGeoJson() {
      fetch("./static/geoJson/jinanhenlong.geojson").then(res => {
        res.json().then(data => {
          console.log(data, "data");
          // 构建建筑路网
          this.loadBuilding(data);
        });
      });
    },
    loadBuilding(data) {
      // 有用的数据只有data中的features
      let features = data.features;

      for (let i = 0; i < features.length; i++) {
        let fel = features[i];

        if (!fel["properties"]) return;

        let info = fel.properties;

        if (info["building"]) {
          this.addBuilding(
            fel.geometry.coordinates,
            info,
            info["building:levels"]
          );
        } else if (info["highway"]) {
          if (
            fel.geometry.type === "LineString" &&
            info["highway"] != "pedestrian" &&
            info["highway"] != "footway" &&
            info["highway"] != "path"
          ) {
            this.addRoad(fel.geometry.coordinates, info);
          }
        }
      }
    },
    // 画动画路径
    getPath(xyPath, yValue) {
      let linePath = [];
      for (let i = 0; i < xyPath.length; i++) {
        const el = xyPath[i];
        linePath.push(new BABYLON.Vector3(el[0], yValue, el[1]));
      }
      return linePath;
    },
    // 画动画帧
    getAnmKeys(linePath) {
      // 动画帧数组
      let keys = [];
      for (let i = 0; i < linePath.length; i++) {
        const linePoint = linePath[i];
        keys.push({
          frame: 0 + i * (100 / linePath.length),
          value: linePoint
        });
      }
      return keys;
    },
    addFlyLine(scene, drone) {
      let xyPath = [
        [3, 5],
        [-4, 3],
        [-2.5, -3],
        [1, -3],
        [1, 5]
      ];
      let linePath = this.getPath(xyPath, 3);
      // 无人机飞行动画
      var animationFly = new BABYLON.Animation(
        "animationFly",
        "position",
        30,
        BABYLON.Animation.ANIMATIONTYPE_VECTOR3,
        BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE
      );
      // 动画帧数组
      let keys = this.getAnmKeys(linePath);
      animationFly.setKeys(keys);
      drone.animations = [];
      drone.animations.push(animationFly);
      let lastKey = 100 - 100 / linePath.length;
      // 参数5动画播放速度
      scene.beginAnimation(drone, 0, lastKey, true, 0.2);
      // const flyLine = BABYLON.MeshBuilder.CreateLines("flyLine", {
      //   points: linePath
      // });
      // flyLine.Color = new BABYLON.Color3(1, 0, 0);
    },
    addSimpleBox(scene) {
      const smallbox = BABYLON.MeshBuilder.CreateBox(
        "smallbox",
        { size: 0.04 },
        scene
      );
      smallbox.position = new BABYLON.Vector3(15, 0, 15);
      smallbox.rotation.y = Math.PI / 3;
      // smallbox.visibility = 0.4;
      let boxMat = new BABYLON.StandardMaterial("boxMat", scene);
      boxMat.emissiveColor = new BABYLON.Color3(1, 0, 0);
      smallbox.material = boxMat;
      return smallbox;
    },
    // 添加box充当小车
    addSimpleCar(scene) {
      let smallbox = this.addSimpleBox(scene);
      // 克隆车 克隆两个box
      let sbox2 = smallbox.clone("sbox2");
      let sbox3 = smallbox.clone("sbox3");
      // 汽车2路径
      let xyPath2 = [
        [-2.3, 5],
        [-2.4, -4]
      ];
      // 汽车3路径
      let xyPath3 = [
        [-2.6, -6],
        [-2.5, 7]
      ];
      // 添加行驶路径动画
      // 汽车路径
      let xyPath = [
        [-3.3, 10],
        [6, -10]
      ];
      // 小车1动画
      this.addCardriveLine(scene, smallbox, xyPath);
      // 小车2动画
      this.addCardriveLine(scene, sbox2, xyPath2);
      // 小车3动画
      this.addCardriveLine(scene, sbox3, xyPath3);
    },
    // 添加汽车动画
    addCarAnim(linePath) {
      // 动画帧数组
      let keys = this.getAnmKeys(linePath);
      // 汽车移动动画
      var animationDrive = new BABYLON.Animation(
        "animationDrive",
        "position",
        30,
        BABYLON.Animation.ANIMATIONTYPE_VECTOR3,
        BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE
      );
      animationDrive.setKeys(keys);
      return animationDrive;
    },
    // 播放汽车动画
    addCardriveLine(scene, smallbox, xyPath) {
      // 车上加灯
      // let light = new BABYLON.PointLight(
      //   "pointLight",
      //   new BABYLON.Vector3(0, 0, 0),
      //   scene
      // );
      // light.parent = smallbox;
      // light.position.y = 0.1;
      // light.diffuse = new BABYLON.Color3(1, 0, 0);
      // light.range = 0.1;
      // light.intensity = 5;
      // 行驶路线三维坐标点连线
      let linePath = this.getPath(xyPath, 0);
      // 行驶动画效果
      let animationDrive = this.addCarAnim(linePath);
      smallbox.animations = [];
      smallbox.animations.push(animationDrive);
      let lastKey = 100 - 100 / linePath.length;
      // 参数5动画播放速度
      scene.beginAnimation(smallbox, 0, lastKey, true, 1);
    },
    // 添加车
    addCar(scene) {
      BABYLON.SceneLoader.ImportMesh(
        "",
        "static/model/car/",
        "carLow.obj",
        scene,
        newMeshes => {
          console.log(newMeshes, "抗");
          const car = BABYLON.Mesh.MergeMeshes(newMeshes.slice(0, 12));
          const carInsideWhell = BABYLON.Mesh.MergeMeshes(
            newMeshes.slice(12, 13)
          );
          console.log(newMeshes.slice(12, 13), "让我看卡");
          let cIWMat = new BABYLON.StandardMaterial("cIWMat", scene);
          cIWMat.diffuseColor = new BABYLON.Color3.White();
          carInsideWhell.material = cIWMat;
          let carboyMat = new BABYLON.StandardMaterial("carBoyMat", scene);
          carboyMat.diffuseColor = new BABYLON.Color3.Red();
          car.material = carboyMat;
          car.position = new BABYLON.Vector3(0, 2, 0);
          // drone.scaling = new BABYLON.Vector3(0.6, 0.6, 0.6);

          console.log(car, "22");
        }
      );
    },
    // 添加无人机
    addDrone(scene) {
      BABYLON.SceneLoader.ImportMesh(
        "",
        "static/model/drone/",
        "Drone_obj.obj",
        scene,
        newMeshes => {
          // Set the target of the camera to the first imported mesh
          //   newMeshes[0].position = new BABYLON.Vector3(3, 10, 0);
          //   console.log(this.myMaterial2, '???')
          //   newMeshes[0].material = this.myMaterial2;
          const drone = BABYLON.Mesh.MergeMeshes(newMeshes);
          drone.position = new BABYLON.Vector3(0, 3, 0);
          drone.scaling = new BABYLON.Vector3(0.6, 0.6, 0.6);

          console.log(drone, "22");
          // let light = new BABYLON.PointLight(
          //   "pointLight",
          //   new BABYLON.Vector3(0, 0, 0),
          //   scene
          // );
          var light = new BABYLON.SpotLight(
            "spotlight",
            new BABYLON.Vector3(0, 0, 0),
            new BABYLON.Vector3(0, -1, 0),
            Math.PI / 3,
            2,
            scene
          );
          light.parent = drone;
          light.diffuse = new BABYLON.Color3(0.5, 1, 0);
          // light.specular = new BABYLON.Color3(1, 1, 0);
          light.range = 500;
          light.intensity = 105;
          this.addFlyLine(scene, drone);
        }
      );
    },
    addRoad(data, info) {
      let points = [];
      for (let i = 0; i < data.length; i++) {
        // 如果不是二维数组
        if (!data[0][1]) return;
        let el = data[i];
        if (!el[0] || !el[1]) return;

        let elp = [el[0], el[1]];

        elp = this.gpsRelativePosition(elp, this.center);

        points.push(new BABYLON.Vector3(elp[0], 0, elp[1]));
      }
      //   const lines = BABYLON.MeshBuilder.CreateLines("lines", {
      //     points: points
      //   });
      const lines = this.createline2d(points);
      lines.rotation.z = Math.PI;
      lines.info = info;
      //   lines.color = new BABYLON.Color3(0.31, 0.31, 0.92);
    },
    // 创建带有宽度的线 接收路径绘制线段
    createline2d(path) {
      // 带有宽度的二维线
      const line = line2D("line2D", {
        path: path,
        width: 0.02
      });
      line.material = this.lineMat;
      return line;
    },

    addBuilding(data, info, height = 5) {
      let shape;
      let holes = [];
      for (let i = 0; i < data.length; i++) {
        let el = data[i];
        // let shape = this.getShape(el, this.center);
        if (i == 0) {
          shape = this.getShape(el, this.center);
        } else {
          holes.push(this.getShape(el, this.center));
        }
      }
      const faceUV = [];
      // 底面
      faceUV[0] = new BABYLON.Vector4(0, 0, 0.01, 0.01);
      // 中间面
      faceUV[1] = new BABYLON.Vector4(0, 0, 1, 1);
      // 顶面
      faceUV[2] = new BABYLON.Vector4(0, 0, 0.01, 0.01);
      const building = BABYLON.MeshBuilder.ExtrudePolygon("building", {
        shape: shape,
        holes: holes,
        depth: 0.05 * height,
        faceUV: faceUV,
        sideOrientation: BABYLON.Mesh.DOUBLESIDE
      });
      building.rotation.z = Math.PI;
      // building.material = this.myMaterial2;
      building.name = info["name"] ? info["name"] : "building";
      building.info = info;
      building.material = this.buildingMat;
      // building.material = this.buildingMat;
      // building.rotation.x = Math.PI;
      // console.log(shape, height, "1");
      // const name =
    },
    getShape(points, center) {
      let shape = [];

      for (let i = 0; i < points.length; i++) {
        let elp = points[i];

        elp = this.gpsRelativePosition(elp, center);

        shape.push(new BABYLON.Vector3(elp[0], 0, elp[1]));
      }
      return shape;
    },
    gpsRelativePosition(objPos, centerPos) {
      // 获取 gps 距离
      let dis = GEOLIB.getDistance(objPos, centerPos);

      // 获取夹角
      let bearing = GEOLIB.getRhumbLineBearing(objPos, centerPos);

      // 计算x
      let x = centerPos[0] + dis * Math.cos((bearing * Math.PI) / 180);

      // 计算y
      let y = centerPos[1] + dis * Math.sin((bearing * Math.PI) / 180);

      return [x / 100, y / 100];
    },
    // 按原始坐标绘制的话，两点之间经纬度差别小，并且坐标点很大数值很大，远离3d引擎的坐标原点（0, 0, 0），需要进行坐标转换，设定中心点，算出各个经纬度点相对中心点的相对坐标
    // 因为地球是球面，小范围内用经纬度点减去原点坐标，不会有相对距离偏差，如果范围大就要将球面坐标，做平面投影，常用的是墨卡托投影

    // babylon创建场景
    /** ***** Add the create scene function ******/
    createScene() {
      // 创建一个场景scene
      var scene = new BABYLON.Scene(this.engine);

      // 添加一个相机，并绑定鼠标事件
      var camera = new BABYLON.ArcRotateCamera(
        "Camera",
        3.75,
        2,
        18,
        new BABYLON.Vector3(0, 0, 0),
        scene
      );
      camera.attachControl(this.canvas, true);
      camera.upperBetaLimit = Math.PI / 2.2;

      // 添加一组灯光到场景
      this.light1 = new BABYLON.HemisphericLight(
        "light1",
        new BABYLON.Vector3(1, 1, 0),
        scene
      );
      //   this.light2 = new BABYLON.PointLight(
      //     "light2",
      //     new BABYLON.Vector3(0, 1, -1),
      //     scene
      //   );
      this.myMaterial = new BABYLON.StandardMaterial("myMaterial", scene);
      this.myMaterial2 = new BABYLON.StandardMaterial("myMaterial2", scene);
      this.myMaterial2.diffuseColor = new BABYLON.Color3(0.2, 0.5, 0.9);
      this.myMaterial.emissiveColor = new BABYLON.Color3(0.5, 0.9, 1);
      this.buildingMat = new BABYLON.StandardMaterial("buildingMat", scene);
      // this.buildingMat.diffuseTexture = new BABYLON.Texture("")
      // this.buildingMat.diffuseColor = new BABYLON.Color3.gray();
      // 路线材质
      this.lineMat = new BABYLON.StandardMaterial("lineMat");
      this.lineMat.diffuseTexture = new BABYLON.Texture(
        "static/textures/flash2.png"
      );
      //   this.lineMat.emissiveColor = new BABYLON.Color3(0.6, 0.8, 1);
      //   建筑材质
      this.buildingMat = new BABYLON.StandardMaterial("buildingMat");
      this.buildingMat.diffuseTexture = new BABYLON.Texture(
        "static/textures/building.png"
        // "static/textures/cyTex2.png"
      );
      //   this.buildingMat.alpha = 0.8;
      //   this.buildingMat.diffuseTexture.vScale = 5;
      //   this.buildingMat.emissiveColor = new BABYLON.Color3(0, 0.8, 1);
      this.buildingMat.emissiveColor = new BABYLON.Color3.White();
      this.getGeoJson(scene);
      this.addDrone(scene);
      // 添加雾
      // scene.fogMode = BABYLON.Scene.FOGMODE_EXP;
      // scene.fogColor = new BABYLON.Color3(0.95, 0.05, 0.05);
      // scene.fogDensity = 0.1;
      scene.registerBeforeRender(() => {
        // console.log(lineMat.diffuseTexture, "为什么");
        // 路线材质动画
        this.lineMat.diffuseTexture.vOffset -= 0.02;
        // 建筑材质动画
        // this.buildingMat.diffuseTexture.vOffset -= 0.01;
      });
      // 创建发光图层  使得物体的 控制物体的emissiveColor 自发光强度，若没有这个图层，亮度自发光亮度无法调节  这个也叫辉光
      let gl = new BABYLON.GlowLayer("glow", scene);
      gl.intensity = 0.2;
      // this.addCar(scene);
      //   this.addSimpleCar(scene);
      scene.onPointerDown = (evt, pickResult) => {
        // if the click hits the ground object, we change the impact position
        if (pickResult.hit) {
          // impact.position.x = pickResult.pickedPoint.x;
          // impact.position.y = pickResult.pickedPoint.y;
          console.log(pickResult.hit, "hit啥", pickResult);
          if (pickResult.pickedMesh.name !== "plane") {
            pickResult.pickedMesh.material = this.myMaterial;
          }
        }
      };

      // 使用粒子系统助手创建粒子系统
      // BABYLON.ParticleHelper.CreateAsync("rain", scene, false).then(set => {
      //   set.start();
      // });

      return scene;
    }
  },
  mounted() {
    this.canvas = document.getElementById("renderCanvas"); // 得到canvas对象的引用
    this.engine = new BABYLON.Engine(this.canvas, true); // 初始化 BABYLON 3D engine

    /** ***** End of the create scene function ******/

    this.scene = this.createScene(); // Call the createScene function

    // 最后一步调用engine的runRenderLoop方案，执行scene.render()，让我们的3d场景渲染起来
    this.engine.runRenderLoop(() => {
      this.scene.render();
    });

    // 监听浏览器改变大小的事件，通过调用engine.resize()来自适应窗口大小
    window.addEventListener("resize", () => {
      this.engine.resize();
    });
    console.log("first");
    // 导出
    // BABYLON.GLTF2Export.GLTFAsync(this.scene, "fileName").then(gltf => {
    //   gltf.downloadFiles();
    // });
  }
};
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="scss">
.wrap {
  height: 100vh;
  width: 100vw;

  #renderCanvas {
    height: 100%;
    width: 100%;
  }
}
</style>
